﻿/* 
 * Copyright (c) 2009 Intel Corporation
 * All rights reserved.
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * -- Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * -- Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * -- Neither the name of the Intel Corporation nor the names of its
 *    contributors may be used to endorse or promote products derived from
 *    this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE INTEL OR ITS
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 * 
 * Contributor: Nathan Letwory
 */

using System;

namespace VerseSharp
{
    public delegate void ObjectTransformRotReal32Callback(ObjectTransformRotReal32Command command);

    public class ObjectTransformRotReal32Command : IVerseCommand
    {
        public CommandID ID { get { return CommandID.ObjectTransformRotReal32; } }
        public uint NodeID;
        public uint TimeS;
        public uint TimeF;
        public byte Mask;
        public float[] Rot = null;
        public float[] Speed = null;
        public float[] Accel = null;
        public float[] DragNormal = null;
        public float Drag = float.NaN;

        public void Deserialize(byte[] source, ref int pos)
        {
            float x, y, z, w;
            NodeID = Utils.GetUInt32(source, ref pos);
            TimeS = Utils.GetUInt32(source, ref pos);
            TimeF = Utils.GetUInt32(source, ref pos);

            Mask = (byte)source[pos++];

            x = Utils.GetReal32(source, ref pos);
            y = Utils.GetReal32(source, ref pos);
            z = Utils.GetReal32(source, ref pos);
            w = Utils.GetReal32(source, ref pos);

            SetRot(x, y, z, w);

            if ((Mask & 1) == 1)
            {
                x = Utils.GetReal32(source, ref pos);
                y = Utils.GetReal32(source, ref pos);
                z = Utils.GetReal32(source, ref pos);
                w = Utils.GetReal32(source, ref pos);
                SetSpeed(x, y, z, w);
            }
            if ((Mask & 2) == 2)
            {
                x = Utils.GetReal32(source, ref pos);
                y = Utils.GetReal32(source, ref pos);
                z = Utils.GetReal32(source, ref pos);
                w = Utils.GetReal32(source, ref pos);
                SetAccel(x, y, z, w);
            }
            if ((Mask & 4) == 4)
            {
                x = Utils.GetReal32(source, ref pos);
                y = Utils.GetReal32(source, ref pos);
                z = Utils.GetReal32(source, ref pos);
                w = Utils.GetReal32(source, ref pos);
                SetDragNormal(x, y, z, w);
            }
            if ((Mask & 8) == 8)
            {
                Drag = Utils.GetReal32(source, ref pos);
            }
        }

        public void SetRot(float x, float y, float z, float w)
        {
            if (Rot == null)
            {
                Rot = new float[4];
            }
            Rot[0] = x;
            Rot[1] = y;
            Rot[2] = z;
            Rot[3] = w;
        }

        public void SetSpeed(float x, float y, float z, float w)
        {
            if (Speed == null)
            {
                Speed = new float[4];
            }
            Speed[0] = x;
            Speed[1] = y;
            Speed[2] = z;
            Speed[3] = w;
        }

        public void SetAccel(float x, float y, float z, float w)
        {
            if (Accel == null)
            {
                Accel = new float[4];
            }
            Accel[0] = x;
            Accel[1] = y;
            Accel[2] = z;
            Accel[3] = w;
        }

        public void SetDragNormal(float x, float y, float z, float w)
        {
            if (DragNormal == null)
            {
                DragNormal = new float[4];
            }
            DragNormal[0] = x;
            DragNormal[1] = y;
            DragNormal[2] = z;
            DragNormal[3] = w;
        }

        public void Serialize(byte[] destination, ref int pos)
        {
            Utils.PutUInt32(destination, ref pos, NodeID);
            Utils.PutUInt32(destination, ref pos, TimeS);
            Utils.PutUInt32(destination, ref pos, TimeF);

            int maskPos = pos;
            pos++;

            /*Mask = (byte)source[pos++];*/

            Utils.PutReal32(destination, ref pos, Rot[0]);
            Utils.PutReal32(destination, ref pos, Rot[1]);
            Utils.PutReal32(destination, ref pos, Rot[2]);
            Utils.PutReal32(destination, ref pos, Rot[3]);

            if (Speed != null)
            {
                destination[maskPos] |= 1;
                Utils.PutReal32(destination, ref pos, Speed[0]);
                Utils.PutReal32(destination, ref pos, Speed[1]);
                Utils.PutReal32(destination, ref pos, Speed[2]);
                Utils.PutReal32(destination, ref pos, Speed[3]);
            }
            if (Accel != null)
            {
                destination[maskPos] |= 2;
                Utils.PutReal32(destination, ref pos, Accel[0]);
                Utils.PutReal32(destination, ref pos, Accel[1]);
                Utils.PutReal32(destination, ref pos, Accel[2]);
                Utils.PutReal32(destination, ref pos, Accel[3]);
            }
            if (DragNormal != null)
            {
                destination[maskPos] |= 4;
                Utils.PutReal32(destination, ref pos, DragNormal[0]);
                Utils.PutReal32(destination, ref pos, DragNormal[1]);
                Utils.PutReal32(destination, ref pos, DragNormal[2]);
                Utils.PutReal32(destination, ref pos, DragNormal[3]);
            }
            if (Drag != float.NaN)
            {
                destination[maskPos] |= 8;
                Utils.PutReal32(destination, ref pos, Drag);
            }
        }
    }
}
